package com.ssy.lingxi.order.serviceimpl.base;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.FundModeEnum;
import com.ssy.lingxi.common.constant.basic.PlatformRuleTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderPayChannelEnum;
import com.ssy.lingxi.common.constant.order.OrderPayTypeEnum;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.*;
import com.ssy.lingxi.order.model.vo.platform.request.PlatformPaymentPayTypeVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformPaymentFundModeVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformPaymentPayChannelVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformPaymentPayTypeDetailVO;
import com.ssy.lingxi.order.repository.*;
import com.ssy.lingxi.order.service.base.IBasePlatformPaymentTypeService;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台后台 - 会员支付策略配置 - 关联的支付方式与渠道相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-08-11
 */
@Service
public class BasePlatformPaymentTypeServiceImpl implements IBasePlatformPaymentTypeService {
    @Resource
    private PlatformPaymentTypeRepository platformPaymentTypeRepository;

    @Resource
    private PlatformPaymentChannelRepository platformPaymentChannelRepository;

    @Resource
    private BaseOrderRuleRepository baseOrderRuleRepository;

    @Resource
    private BaseOrderPayChannelRepository baseOrderPayChannelRepository;

    @Resource
    private PlatformPaymentRepository platformPaymentRepository;

    @Resource
    private IBasePlatformPaymentTypeService basePlatformPaymentTypeService;

    @Resource
    private PlatformPaymentMemberRepository platformPaymentMemberRepository;

    /**
     * 校验、保存会员支付策略关联的支付方式、支付渠道
     *
     * @param platformPayment 会员支付策略
     * @param payTypes        支付方式与渠道
     * @param isCreate        是否新增， true-新增，false-更新
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkPayTypes(PlatformPaymentDO platformPayment, List<PlatformPaymentPayTypeVO> payTypes, boolean isCreate) {
        //Step 1: 校验是否有重复值
        if(payTypes.size() != payTypes.stream().map(PlatformPaymentPayTypeVO::getPayType).distinct().count()) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_TYPE_DUPLICATE);
        }

        //Step 2: 如果是更新，删除后再新增
        if(!isCreate) {
            platformPaymentTypeRepository.deleteByPayment(platformPayment);
        }

        //Step 2: 新增
        List<PlatformPaymentTypeDO> paymentTypes = payTypes.stream().filter(payType -> !CollectionUtils.isEmpty(payType.getPayChannels())).sorted(Comparator.comparingInt(PlatformPaymentPayTypeVO::getPayType)).map(payType -> {
            PlatformPaymentTypeDO paymentType = new PlatformPaymentTypeDO();
            paymentType.setPayment(platformPayment);
            paymentType.setFundMode(payType.getFundMode());
            paymentType.setPayType(payType.getPayType());
            paymentType.setPayTypeName(OrderPayTypeEnum.getNameByCode(payType.getPayType()));
            platformPaymentTypeRepository.saveAndFlush(paymentType);

            List<PlatformPaymentChannelDO> payChannels = payType.getPayChannels().stream().map(payChannel -> {
                PlatformPaymentChannelDO paymentChannel = new PlatformPaymentChannelDO();
                paymentChannel.setPayChannel(payChannel);
                paymentChannel.setPayChannelName(OrderPayChannelEnum.getNameByCode(payChannel));
                paymentChannel.setPayType(paymentType);
                return paymentChannel;
            }).collect(Collectors.toList());
            platformPaymentChannelRepository.saveAll(payChannels);

            paymentType.setPayChannels(new HashSet<>(payChannels));
            return paymentType;
        }).collect(Collectors.toList());


        platformPaymentTypeRepository.saveAll(paymentTypes);

        //Step 4: 设置关联，调用方保存PlatformPaymentDO
        platformPayment.setPayTypes(new HashSet<>(paymentTypes));
        return Wrapper.success();
    }

    /**
     * 查询会员支付策略关联的支付方式、支付渠道
     *
     * @param platformPayment 会员支付策略
     * @return 查询结果
     */
    @Override
    public List<PlatformPaymentPayTypeDetailVO> findPayTypes(PlatformPaymentDO platformPayment) {
        List<PlatformPaymentTypeDO> paymentTypes = platformPaymentTypeRepository.findByPayment(platformPayment, Sort.by("payType").ascending());
        if(CollectionUtils.isEmpty(paymentTypes)) {
            return new ArrayList<>();
        }

        //Step 1: 查找平台基础规则配置中的资金归集模式
        List<PlatformPaymentFundModeVO> fundModes = baseOrderRuleRepository.findByRuleTypeAndStatus(PlatformRuleTypeEnum.FUND.getCode(), EnableDisableStatus.ENABLE.getCode()).stream().map(ruleType -> new PlatformPaymentFundModeVO(ruleType.getMethodCode(), ruleType.getMethodName())).collect(Collectors.toList());

        //Step 2: 查找支付方式
        List<BaseOrderPayChannelDO> orderPayChannels = baseOrderPayChannelRepository.findByStatus(EnableDisableStatus.ENABLE.getCode());

        //Step 3: 拼接查询结果
        return paymentTypes.stream().map(paymentType -> {
            PlatformPaymentPayTypeDetailVO detailVO = new PlatformPaymentPayTypeDetailVO();
            detailVO.setPayType(paymentType.getPayType());
            detailVO.setPayTypeName(paymentType.getPayTypeName());
            //线上支付、线下支付、通联支付、跨境电商进口支付，资金归集模式可以为“平台代收”或“会员直接到账”，
            //授信额度支付只能是“会员直接到账”
            //建行支付只能是“平台代收”
            if(detailVO.getPayType().equals(OrderPayTypeEnum.ONLINE_PAYMENT.getCode()) || detailVO.getPayType().equals(OrderPayTypeEnum.OFFLINE_PAYMENT.getCode()) || detailVO.getPayType().equals(OrderPayTypeEnum.ALLIN_PAY.getCode()) || detailVO.getPayType().equals(OrderPayTypeEnum.COMMERCE_IMPORT_PAY.getCode())) {
                detailVO.setFundModes(fundModes);
            } else if(detailVO.getPayType().equals(OrderPayTypeEnum.CREDIT_LINE_PAYMENT.getCode())){
                detailVO.setFundModes(fundModes.stream().filter(fundMode -> fundMode.getFundMode().equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode())).collect(Collectors.toList()));
            } else if(detailVO.getPayType().equals(OrderPayTypeEnum.CCB_PAY.getCode())) {
                detailVO.setFundModes(fundModes.stream().filter(fundMode -> fundMode.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode())).collect(Collectors.toList()));
            }

            detailVO.setFundMode(paymentType.getFundMode());
            detailVO.setChannels(orderPayChannels.stream().filter(orderPayChannel -> orderPayChannel.getPayType().equals(paymentType.getPayType())).map(orderPayChannel -> {
                PlatformPaymentPayChannelVO channelVO = new PlatformPaymentPayChannelVO();
                channelVO.setPayChannel(orderPayChannel.getPayChannel());
                channelVO.setPayChannelName(orderPayChannel.getPayChannelName());
                return channelVO;
            }).collect(Collectors.toList()));
            detailVO.setPayChannels(paymentType.getPayChannels().stream().map(PlatformPaymentChannelDO::getPayChannel).sorted(Comparator.naturalOrder()).collect(Collectors.toList()));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 查询会员线下支付的支付策略的资金归集模式
     * @param memberId   会员id
     * @param roleId     角色id
     * @return
     */
    public Integer getFundModeByMemberIdAndRoleId(Long memberId, Long roleId) {
        //查询会员支付策略配置
        PlatformPaymentDO platformPaymentDO = platformPaymentRepository.findFirstByAllMembersAndStatus(Boolean.TRUE, 1);
        List<PlatformPaymentPayTypeDetailVO> payTypes = null;
        if (Objects.nonNull(platformPaymentDO)) {
            payTypes = basePlatformPaymentTypeService.findPayTypes(platformPaymentDO);
        } else {
            PlatformPaymentMemberDO platformPaymentMemberDO = platformPaymentMemberRepository.findFirstByMemberIdAndRoleId(memberId, roleId);
            PlatformPaymentDO payment = platformPaymentMemberDO.getPayment();
            payTypes = basePlatformPaymentTypeService.findPayTypes(payment);
        }
        PlatformPaymentPayTypeDetailVO payTypeDetailVO = payTypes.stream().filter(payType -> OrderPayTypeEnum.OFFLINE_PAYMENT.getCode().equals(payType.getPayType())).findFirst().orElse(null);
        Integer fundMode = payTypeDetailVO.getFundMode();
        return fundMode;
    }
}
